package com.zc.portal.infra.security.filter;

import com.alibaba.fastjson.JSON;
import com.zc.commons.pojo.ResponseData;
import com.zc.portal.domain.dto.SysUser;
import com.zc.portal.domain.pojo.LoginUser;
import com.zc.portal.domain.pojo.PcmcUser;
import com.zc.portal.infra.security.exception.LoginRequestInfoException;
import com.zc.portal.infra.security.jwt.SecurityJwtUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;

public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

    public JwtLoginFilter(String loginUrl) {
        this.setFilterProcessesUrl(loginUrl);
    }

    public JwtLoginFilter(AuthenticationManager authenticationManager) {
        this.setAuthenticationManager(authenticationManager);
    }

    public JwtLoginFilter(String loginUrl, AuthenticationManager authenticationManager) {
        this.setFilterProcessesUrl(loginUrl);
        this.setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {


        if (!"POST".equals(request.getMethod().toUpperCase())) {
            throw new AuthenticationServiceException("非法登录请求！");
        }
        LoginUser loginUser = getLoginUser(request);
        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(loginUser.getUserCode(), loginUser.getPassword());
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    public JwtLoginFilter applyProcessesUrl(String loginUrl) {
        this.setFilterProcessesUrl(loginUrl);
        return this;
    }

    public JwtLoginFilter applyAuthenticationManager(AuthenticationManager authenticationManager) {
        this.setAuthenticationManager(authenticationManager);
        return this;
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse resp, FilterChain chain, Authentication auth) throws IOException, ServletException {
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json");
        String tokenContent = SecurityJwtUtils.createjwtToken((SysUser) auth.getPrincipal(), false);
        ResponseData responseData = new ResponseData();
        responseData.setCode(HttpStatus.OK.value());
        HashMap<String, String> token = new HashMap<>();
        token.put("token", tokenContent);
        responseData.setMessage("Login Success!");
        responseData.setData(token);
        String jsonString = JSON.toJSONString(responseData);
        PrintWriter printWriter = resp.getWriter();
        printWriter.write(jsonString);
        if (printWriter != null) {
            printWriter.flush();
            printWriter.close();
        }
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json");
        //认证失败
        int code = HttpStatus.MULTIPLE_CHOICES.value();
        String msg = null;
        if (e instanceof BadCredentialsException) {
            msg = "密码错误！";
        } else if (e instanceof UsernameNotFoundException) {
            msg = "用户不存在！";
        } else {
            code = HttpStatus.INTERNAL_SERVER_ERROR.value();
            msg = "服务器内部错误！";
        }
        ResponseData responseData = new ResponseData();
        responseData.setCode(code);
        responseData.setMessage("登录失败!" + msg);
        responseData.setData(e.getMessage());
        String jsonString = JSON.toJSONString(responseData);
        PrintWriter printWriter = resp.getWriter();
        printWriter.write(jsonString);
        if (printWriter != null) {
            printWriter.flush();
            printWriter.close();
        }
    }

    private LoginUser getLoginUser(HttpServletRequest request) throws AuthenticationException {
        String requestBody = null;
        BufferedReader reader = null;
        StringBuilder sb;
        try {
            reader = request.getReader();
            sb = new StringBuilder();
            String str;
            while ((str = reader.readLine()) != null) {
                sb.append(str);
            }
            requestBody = sb.toString();
        } catch (IOException e) {
            this.logger.error("登录获取请求数据异常！", e);
            throw new LoginRequestInfoException("获取登录参数异常！", e);
        } finally {
            IOUtils.closeQuietly(reader);
        }
        LoginUser loginUser = JSON.parseObject(requestBody, LoginUser.class);
        return loginUser;
    }

    private void resetSysUser(SysUser sysUser) {
        sysUser.setPassword(null);
    }


}
